#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

using Weazel.Math;
using System.IO;

namespace Weazel.Gezel.Simulator.Reference
{
    /// <summary>
    /// Just as Stimuli can be used to drive a signal from
    /// file values, the tracerblock performs the opposite 
    /// process - outputs signal values to file. This is
    /// useful for debugging, verification and recording
    /// stimuli values
    /// </summary>
    class TracerBlock
    {
        private Symid id; // Used to identify trace to ValueChangeDump

        /// <summary>
        /// The name of the file which
        /// recieves tracing output
        /// </summary>
        private readonly string filename;
        public string Filename
        {
            get
            {
                return filename;
            }
        }

        /// <summary>
        /// References the signal being traced
        /// </summary>
        private readonly AbstractSignal signal;

        /// <summary>
        /// The stream used to output traced values on
        /// </summary>
        private StreamWriter writer;

        private Integer value;

        private readonly ValueChangeDump dump;

        public TracerBlock(string filename, AbstractSignal signal)
        {
            this.filename = filename;
            this.signal = signal;
            this.value = new Integer((int)signal.Width(), signal.Signed() == 1);

            writer = new StreamWriter(filename, false);
            //writer.AutoFlush = true;
        }

        public TracerBlock(string filename, AbstractSignal signal, ValueChangeDump dump) : this(filename, signal)
        {
            if (dump != null)
            {
                this.dump = dump;
                id = dump.RegisterTracer(signal);
            }
        }

        /// <summary>
        /// Evaluates the block by tracing the current
        /// value of the signal to the file and optionally
        /// forwardning the value to the ValueChangeDump.
        /// </summary>
        /// <param name="generation"></param>
        public void Evaluate(long generation)
        {
            value.ValueCopy(signal.Evaluate(null, generation));
            writer.WriteLine(value.ToBinaryString());

            // NOTE: Official gezel impl. reevaluates signal.
            // which seems to be a waste of performance
            if (dump != null)
                dump.Update(id, value);
        }

        /// <summary>
        /// Flushes the stream and closes it
        /// </summary>
        public void CloseStream()
        {
            if (writer != null)
            {
                writer.Flush();
                writer.Close();
                writer = null;
            }
        }
    }
}